package com.dragon.refect.classload;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;

/**
 * 自定义类加载器
 *
 * @author dragon
 * @since 2019/11/21
 */
public class MyClassLoader extends ClassLoader {

    /**
     * class文件的扩展名
     */
    private static final String FILE_EXTENSION_NAME = ".class";

    /**
     * 类加载器名称
     */
    private String classLoaderName;

    /**
     * 根路径
     */
    private String path;

    /**
     * 默认的父类加载器是系统类加载器AppClassLoader
     *
     * @param classLoaderName 类加载器名称
     */
    public MyClassLoader(String classLoaderName) {
        super();
        this.classLoaderName = classLoaderName;
    }

    /**
     * 自定义该类加载器的父类加载器
     *
     * @param parent          父类加载器
     * @param classLoaderName 类加载器名称
     */
    public MyClassLoader(ClassLoader parent, String classLoaderName) {
        super(parent);
        this.classLoaderName = classLoaderName;
    }

    @Override
    public Class findClass(String name) {
        System.out.println("findClass");

        byte[] classData = loadClassData(name);

        return defineClass(name, classData, 0, classData.length);
    }

    /**
     * 通过指定的全类名去找到class文件
     *
     * @param name 全类名
     * @return class字节码byte数组
     */
    private byte[] loadClassData(String name) {
        System.out.println("loadClassData");

        InputStream      is    = null;
        byte[]           array = null;
        ByteOutputStream bos   = null;

        try {
            byte[] buffer = new byte[1024];

            is  = new FileInputStream(new File(this.path.concat(name.replace(".", "/")).concat(FILE_EXTENSION_NAME)));
            bos = new ByteOutputStream(1024 * 2);

            int ch;

            while ((ch = is.read(buffer)) != -1) {
                bos.write(buffer, 0, ch);
            }

            array = bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }

                if (bos != null) {
                    bos.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return array;
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader classLoader = new MyClassLoader("myClassLoader");

        classLoader.setPath("/Users/panlong/Downloads/");
        System.out.println("classLoader:" + classLoader);

        Class<?> clazz = classLoader.loadClass("com.dragon.refect.classload.ClassInitialization");

        System.out.println("MyTest3:" + clazz);
        System.out.println("MyTest3 hashcode:" + clazz.hashCode());
        System.out.println("==================");

        MyClassLoader classLoader2 = new MyClassLoader("myClassLoader");

        classLoader2.setPath("/Users/panlong/Downloads/");
        System.out.println("classLoader:" + classLoader2);

        Class<?> clazz2 = classLoader2.loadClass("com.dragon.refect.classload.ClassInitialization");

        System.out.println("MyTest3:" + clazz2);
        System.out.println("MyTest3 hashcode:" + clazz2.hashCode());
    }

    public static void test(ClassLoader classLoader) throws Exception {
        Class<?> clazz = classLoader.loadClass("com.dragon.refect.classload.MyTest7");

        System.out.println(clazz);
    }

    public void setPath(String path) {
        this.path = path;
    }
}


//~ Formatted by Jindent --- http://www.jindent.com
